from datetime import datetime

import numpy as np
from pytz import timezone
from client import es_client
from client.redis_client import r
from model.es.card import ClockRuleTime, ElectronicCardModel
from model.wristband_models import LocationData
from utils.date_utils import DateTimeCombiner, date_time_to_str_000z, timestamp_to_str_000z
from utils.logger_util import logger
from utils.mongo_util import db


async def save_clock_in(state: int, schedule: dict, location: dict, clock_in_state: str):
    """
        :param clock_in_state:
        :param state:
        :param schedule:
        :param location:
        :return:
    """
    es = await es_client.get_es_client()
    dt = schedule['dt']
    rule_time = schedule['clockRule'][0]['ruleTime'][state]  # 后续根据state 调整获取的时间。
    dt_result = DateTimeCombiner.combine(dt, rule_time['clockInTime'])
    punch_in_time = datetime.fromtimestamp(location['timestamp'])
    new_clock_record = await mapping_clock_record(clock_in_state, location, punch_in_time, rule_time)
    if state == 0:  # 状态是0则保存整体数据
        attendance_data = await mapping_full_data(dt_result, new_clock_record, schedule)
        document = await es.index_document('p_clock_record', attendance_data)
        r.hset('state_' + schedule['imei'], '_id', document['_id'])
        r.hset('state_' + schedule['imei'], 'state', 1)
    else:
        _id = r.hget('state_' + schedule['imei'], '_id')
        await add_clock_record(new_clock_record, _id)


async def mapping_full_data(dt_result, new_clock_record, schedule):
    clock_record = [new_clock_record]
    attendance_data = {
        "dt": dt_result,
        "dataAuthority": schedule['dataAuthority'],
        "attendanceShiftSize": len(schedule['clockRule']),
        "clockRuleName": schedule['clockRule'][0]['ruleName'],
        "nickName": schedule['name'],
        "attendanceGroupName": schedule['attendanceGroupName'],
        "imei": schedule['imei'],
        "id": schedule['id'],
        "clockRecord": clock_record,
        "userName": "",
        "depart": schedule['departId'],
        "departName": schedule['departName']
    }
    return attendance_data


async def mapping_full_data_new(dt_result, new_clock_record, card: ElectronicCardModel):
    clock_record = new_clock_record
    return {
        "dt": dt_result,
        "dataAuthority": card.dataAuthority.model_dump(),
        "attendanceShiftSize": len(card.clock_rule),
        "clockRuleName": card.clock_rule[0].rule_name,
        "nickName": card.nick_name,
        "attendanceGroupName": card.attendance_group_name,
        "imei": card.imei,
        "id": card.id,
        "clockRecord": clock_record,
        "userName": card.name,
        "depart": card.depart,
        "departName": card.depart_name,
        "jobPost": card.job_post
    }


async def mapping_clock_record(clock_in_state, location, punch_in_time, rule_time):
    new_clock_record = {
        "ruleTime": rule_time['clockInTime'] + ":00",
        "punchInTime": date_time_to_str_000z(punch_in_time),
        "state": clock_in_state,
        "punchInLnt": np.float64(location["longitude"]),
        "punchInLat": np.float64(location["latitude"]),
        "nextDay": rule_time['nextDay']
    }
    return new_clock_record


async def get_clock_record(start_time: datetime, end_time: datetime, imei: list):
    start_date = date_time_to_str_000z(start_time)
    end_date = date_time_to_str_000z(end_time)
    query = {
        "size": 1,
        "query": {
            "bool": {
                "must": [
                    {
                        "terms": {
                            "imei": imei
                        }
                    }, {
                        "range": {
                            "dt": {
                                "gte": start_date,
                                "lte": end_date
                            }
                        }
                    }
                ],
                "must_not": [
                    {
                        "term": {
                            "validState": {
                                "value": 0
                            }
                        }
                    }
                ]
            }
        },
        "sort": [
            {
                "dt": {
                    "order": "desc"
                }
            }
        ]
    }
    es = await es_client.get_es_client()
    return await es.search_documents_have_id(index="p_clock_record", query=query)


async def get_clock_record_mongo(start_time: datetime, end_time: datetime, imei_list: list):
    beijing_tz = timezone('Asia/Shanghai')
    start_date = start_time.astimezone(beijing_tz)
    end_date = end_time.astimezone(beijing_tz)
    query_filter = {
        "imei": {"$in": imei_list},
        "dt": {
            "$gte": start_date,
            "$lte": end_date
        },
        "validState": {"$ne": 0}
    }
    # 4. 执行查询并排序（按 dt 降序）
    result = list(db.p_clock_record.find(query_filter).sort("dt", -1))
    return result


async def mapping_clock_record_new(location: LocationData, rule_time: ClockRuleTime, clock_in_state):
    # beijing_tz = timezone('Asia/Shanghai')
    # date = datetime.fromtimestamp(data['timestamp'], beijing_tz)
    new_clock_record = {
        "ruleTime": rule_time.clock_in_time + ":00",
        "punchInTime": timestamp_to_str_000z(location.timestamp),
        "state": clock_in_state,
        "punchInLnt": np.float64(location.longitude),
        "punchInLat": np.float64(location.latitude),
        "nextDay": rule_time.next_day
    }
    return new_clock_record


async def add_clock_record_mongo(new_clock_record_list: list, _id: str):
    # 3. 构建Update请求体
    for new_clock_record in new_clock_record_list:
        db.p_clock_record.update_one(
            {"_id": _id},
            {"$push": {"clockRecord": new_clock_record}}  # 使用 $each 批量添加
        )


async def add_clock_record(new_clock_record: dict, _id: str):
    # 3. 构建Update请求体
    update_body = {
        "script": {
            "source": """
                if (ctx._source.clockRecord  == null) { 
                    ctx._source.clockRecord  = [params.new_record] 
                } else { 
                    ctx._source.clockRecord.add(params.new_record)  
                }
            """,
            "lang": "painless",
            "params": {"new_record": new_clock_record}
        }
    }

    # 4. 执行更新操作
    es = await es_client.get_es_client()
    try:
        await es.update(
            index="p_clock_record",
            _id=_id,
            body=update_body
        )
        logger.info(f'更新成功p_clock_record，{_id}update_body')
    except Exception as e:
        logger.error(f'异常{e}')


async def add_clock_record_new(new_clock_record: dict, _id: str):
    # 构建Update请求体
    update_body = {
        "script": {
            "source": """
                if (ctx._source.clockRecord  == null) { 
                    ctx._source.clockRecord  = [params.new_record] 
                  } else { 
                    ctx._source.clockRecord.add(params.new_record)  
                }
            """,
            "lang": "painless",
            "params": {"new_record": new_clock_record}
        }
    }

    # 4. 执行更新操作
    es = await es_client.get_es_client()
    try:
        await es.update(
            index="p_clock_record",
            _id=_id,
            body=update_body
        )
        logger.info(f'更新成功p_clock_record，{_id}update_body')
    except Exception as e:
        logger.error(f'异常{e}')


